/**
 * @file 创建axios实例，封装定制axios
 */
import axios from 'axios';
import type { AxiosResponse } from 'axios';
import { message } from 'ant-design-vue';
import { storage } from '@/utils/LocalStorage.ts';
import { router } from '@/router';

// 创建 axios 实例
const service = axios.create({
  baseURL: `${import.meta.env.VITE_API_BASE_URL}/api`,
  timeout: 80000000, // 请求超时时间
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
});

function toLogin() {
  router.push({ path: '/login' });
}
function toPage404() {
  router.push({ path: '/404' });
}

function toPage403() {
  router.push({ path: '/403' });
}

/**
 * 请求失败后的错误统一处理
 * @param {Number} status 请求失败的 HTTP 状态码
 */
const errorHandle = (status: number, other: string) => {
  // 服务器响应的 HTTP 状态码判断
  switch (status) {
    // 401: 未登录状态，跳转登录页
    case 401:
      storage.removeAll();
      toLogin();
      break;
    // 403 token过期
    // 清除所有信息并跳转登录页
    case 403:
      storage.removeAll();
      setTimeout(() => {
        toPage403();
      }, 1000);
      break;
    // 404请求不存在
    case 404:
      console.log('请求的资源不存在');
      toPage404();
      break;
    default:
      console.log(other);
  }
};

// 输出失败响应（响应成功，但结果是失败的）
const printFailRes = function (axiosRes: AxiosResponse) {
  if (axiosRes.status === 200 && axiosRes.data.code !== 0) {
    console.error(`请求异常的接口:${axiosRes.config && axiosRes.config.url}`);
    console.error(`错误信息: ${axiosRes.data.msg}`);

    const { code, msg } = axiosRes.data;
    switch (code) {
      // 系统操作失败
      case 1000:
        message.error(msg || '操作失败');
        break;
      // 请重新登录
      case 1001:
        storage.removeAll();
        message.warn('登录失效，请重新登录');
        setTimeout(() => {
          toLogin();
        }, 1000);
        break;
      // 接口调用失败
      case 2000:
        message.error(msg || '接口调用失败');
        break;
    }
  }
};

// 输出错误响应
const printErrorRes = function (error: AxiosResponse) {
  console.error(`请求异常的接口:${error.config && error.config.url}`);
  console.error(`错误信息： ${error}`);
};

// 输出响应
const printResponse = function (res: AxiosResponse) {
  if (res.data) {
    printFailRes(res);
  } else {
    printErrorRes(res);
  }
};

// 响应拦截器
service.interceptors.response.use(
  (res: AxiosResponse) => {
    // 2xx 范围内的状态码都会触发该函数.
    printResponse(res);
    if (res.status === 200) {
      return Promise.resolve(res.data);
    } else {
      return Promise.reject(res);
    }
  },
  (error) => {
    // 超出 2xx 范围的状态码都会触发该函数.
    const { response } = error;
    printResponse(response);
    if (response) {
      // 请求已发出，但是不在2xx的范围
      errorHandle(response.status, response.data.msg);
      toLogin();
      return Promise.reject(response);
    } else {
      // 处理断网的情况
      // eg:请求超时或断网时，更新state的network状态
      // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
      // 关于断网组件中的刷新重新获取数据，会在断网组件中说明
      if (!window.navigator.onLine) {
        // store.commit('changeNetwork', false);
        console.log('changeNetwork');
      } else {
        return Promise.reject(new Error(error));
      }
    }
  },
);

// 不需要携带 token 的接口 URL（登录和注册接口）
const noNeedTokenApiUrl = [
  '/client/sys/user/login-by-username',
  '/client/sys/user/register-login-by-verify-code',
  '/client/bus/team/get-invite-code-info',
  '/client/bus/board/get-invite-code-info',
];

// 请求拦截器
service.interceptors.request.use(
  (config) => {
    // 除登录注册请求外，每个请求均在请求头添加 satoken
    if (
      storage.get('satoken') &&
      config.url &&
      !noNeedTokenApiUrl.includes(config.url)
    ) {
      config.headers.satoken = storage.get('satoken');
    }
    return config;
  },
  (error) => {
    // Do something with request error
    console.log('request error'); // for debug
    Promise.reject(error);
  },
);

export default service;
